﻿using System.Collections;
using System.Linq;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.U2D;
using UnityEditor.U2D;
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities.Editor;
using Sirenix.Utilities;
using UnityEngine.Serialization;

// ReSharper disable once CheckNamespace
public class ImageCompressionEditorTool : OdinEditorWindow
{
    //- "Standalone"：独立平台（Windows、Mac、Linux等） 
    //- "iPhone"：iOS平台 
    //- "Android"：Android平台 
    //- "Web"：Web平台 
    //- "WebGL"：WebGL平台 
    //- "Windows Store Apps"：Windows商店应用平台 
    //- "PS4"：PlayStation 4平台 
    //- "XboxOne"：Xbox One平台 
    //- "tvOS"：tvOS平台 
    //- "Switch"：Nintendo Switch平台 
    //- "Lumin"：Magic Leap Lumin平台 
    //- "WSA"：Windows Store Apps平台 
    //- "UWP"：Universal Windows Platform平台 
    //- "PS5"：PlayStation 5平台 
    //- "XboxSeries"：Xbox Series X/S平台
    
    private const TextureImporterFormat AtlasFormat = TextureImporterFormat.ASTC_8x8;

    private readonly string[] _imageExtensions = {".png", ".jpg", ".jpeg", ".bmp", ".tga"};

    private int MaxTextureSize 
    {
        get 
        {
            switch (size)
            {
                case 1:
                    return 32;
                case 2:
                    return 64;
                case 3:
                    return 128;
                case 4:
                    return 256;
                case 5:
                    return 512;
                case 6:
                    return 1024;
                case 7:
                    return 2048;
                case 8:
                    return 4096;
                case 9:
                    return 8192;
                default: return 1024;
            }
        } 
    }
    
    private static IEnumerable CompressType = new ValueDropdownList<int>
    {
        { "ASTC_Automatic", 1},
        { "Default", 2}
    };

    private static IEnumerable CompressSize = new ValueDropdownList<int>
    {
        { "32", 1},
        { "64", 2},
        { "128", 3},
        { "256", 4},
        { "512", 5},
        { "1024", 6},
        { "2048", 7},
        { "4096", 8},
        { "8192", 9}
    };
    
    private static IEnumerable ASTCCompressSize = new ValueDropdownList<int>() {
        { "4×4", (int)TextureImporterFormat.ASTC_4x4},
        { "5×5", (int)TextureImporterFormat.ASTC_5x5},
        { "6×6", (int)TextureImporterFormat.ASTC_6x6},
        { "8×8", (int)TextureImporterFormat.ASTC_8x8},
        { "10×10", (int)TextureImporterFormat.ASTC_10x10},
        { "12×12", (int)TextureImporterFormat.ASTC_12x12},
    };
    
    [MenuItem("Tools/资源优化工具/纹理压缩工具")]
    static void TextureCompress()
    {
        ImageCompressionEditorTool window = GetWindow<ImageCompressionEditorTool>();
        window.folderPath = new List<string>();
        window.position = GUIHelper.GetEditorWindowRect().AlignCenter(600, 500);
        window.titleContent = new GUIContent("纹理压缩工具");
    }

    #region GUI

    [Title("选择压缩格式：")]
    [HideLabel]
    [GUIColor(0.26f, 1, 0)]
    [ValueDropdown("CompressType")]
    public int type = 1;

    [Title("选择纹理最大尺寸：")]
    [HideLabel]
    [GUIColor(0.26f, 1, 0)]
    [ValueDropdown("CompressSize")]
    public int size = 6;

    [FormerlySerializedAs("isManualAstc")]
    [ShowIf("@type==1")]
    [Title("是否手动设置ASTC压缩比(越大压缩比例越大，图片越小)：")]
    [HideLabel]
    public bool isManualAstc;
    
    [PropertySpace(20)]
    [Title("强制压缩(是否不忽略已经压缩过的图片)：")]
    [HideLabel]
    public bool forceCompress;

    [ShowIf("@isManualAstc")]
    [GUIColor(0.26f, 1, 0)]
    [Title("ASTC压缩比：")]
    [HideLabel]
    [ValueDropdown("ASTCCompressSize")]
    public int astcSize = 3;

    [PropertySpace(20)]
    [Title("选择压缩路径")]
    [HideLabel]
    [FolderPath]
    public List<string> folderPath = new();
    
    [PropertySpace(20)]
    [Button("开始压缩")]
    private void CompressImages()
    {
        if (folderPath.Count == 0) 
        {
            EditorUtility.DisplayDialog("执行异常", "请先选择一个文件夹再压缩!", "确认", "取消");
            return;
        }

        List<string> filePaths = new List<string>();
        List<string> atlasPaths = new List<string>();
        
        foreach (var path in folderPath)
        {
            List<string> crtFilePaths = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).Where(file => _imageExtensions.Contains(Path.GetExtension(file).ToLower())).ToList();
            filePaths.AddRange(crtFilePaths);
            
            List<string> crtAtlasPaths = Directory.GetFiles(path, "*.spriteatlas", SearchOption.AllDirectories).ToList();
            atlasPaths.AddRange(crtAtlasPaths);
        }

        string crtCompressDes = type == 1 ? "ASTC" : "Default";

        if (filePaths.Count > 0)
        {
            EditorUtility.DisplayProgressBar("正在检测纹理...", "", 0f);
            
            int index = 1;
            float per = 1 / (float)filePaths.Count;

            foreach (string filePath in filePaths)
            {
                string relativePath = filePath.Replace("\\", "/");
                TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(relativePath);
                if (importer == null)
                {
                    continue;
                }
                
                bool hasChanged = SetTextureFormat(importer, relativePath);
                if (hasChanged)
                {
                    EditorUtility.DisplayProgressBar(crtCompressDes, $"{relativePath}该资源已设置压缩格式...", index * per);
                }
                
                EditorUtility.DisplayProgressBar(crtCompressDes, $"{relativePath}正在设置压缩格式...", index * per);
                
                index++;
            }
            
            EditorUtility.ClearProgressBar();
        }

        //图集本身生成后就已经压缩 鉴于其压缩时间 先不进行压缩处理
        if (atlasPaths.Count > 0)
        {
            EditorUtility.DisplayProgressBar("正在检测图集...", "", 0f);
            
            int index = 1;
            float per = 1 / (float)atlasPaths.Count;
        
            foreach (var atlasPath in atlasPaths)
            {
                string relativePath = atlasPath.Replace("\\", "/");
                SpriteAtlas atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(relativePath);
                
                if (atlas != null)
                {
                    TextureImporterFormat format = type == 1 ? AtlasFormat : TextureImporterFormat.ETC2_RGBA8;
                    SetAtlasFormat(atlas, format, relativePath);
                    EditorUtility.DisplayProgressBar(crtCompressDes, $"{relativePath}正在设置压缩格式...", index * per);
                    index++;
                }
            }
            
            EditorUtility.ClearProgressBar();
        }
        
        AssetDatabase.Refresh();
        
        EditorUtility.DisplayDialog("", "压缩成功!", "确认", "取消");
    }

    #endregion

    
    private TextureImporterFormat GetTextureFormat(TextureImporter importer)
    {
        switch (type)
        {
            case 1:
                if (isManualAstc && astcSize > 0) 
                {
                    return (TextureImporterFormat)astcSize;
                }

                if (importer.DoesSourceTextureHaveAlpha())
                {
                    return TextureImporterFormat.ASTC_5x5;
                }

                if (importer.textureType == TextureImporterType.NormalMap)
                {
                    return TextureImporterFormat.ASTC_4x4;
                }

                return TextureImporterFormat.ASTC_6x6;
            case 2:
                return TextureImporterFormat.ETC2_RGBA8;
            default: return TextureImporterFormat.ETC2_RGBA8;
        }
    }
    
    private bool SetTextureFormat(TextureImporter importer, string texturePath)
    {
        bool hasChanged = false;
        importer.textureCompression = TextureImporterCompression.Compressed;
        int maxSize = Mathf.Min(importer.maxTextureSize, MaxTextureSize);
        
        if (MaxTextureSize > 1024)
        {
            maxSize = MaxTextureSize;
        }

        TextureImporterFormat format = TextureImporterFormat.Automatic;
        
        //设置IOS
        if (TrySetPlatformFormat(importer, format, "iPhone", maxSize))
        {
            hasChanged = true;
        }

        //设置Android
        if (TrySetPlatformFormat(importer, format, "Android", maxSize))
        {
            hasChanged = true;
        }
        
        //webGL平台
        if (TrySetPlatformFormat(importer, format, "WebGL", maxSize))
        {
            hasChanged = true;
        }

        if (hasChanged)
        {
            //设置默认平台
            TextureImporterPlatformSettings defaultSettings = importer.GetDefaultPlatformTextureSettings();
            defaultSettings.format = TextureImporterFormat.Automatic;
            defaultSettings.maxTextureSize = maxSize;
            
            importer.SetPlatformTextureSettings(defaultSettings);
            
            AssetDatabase.ImportAsset(texturePath);
        }

        return hasChanged;
    }

    private void SetAtlasFormat(SpriteAtlas atlas, TextureImporterFormat format, string atlasPath)
    {
        //IOS
        TextureImporterPlatformSettings iosPlatformSettings = new TextureImporterPlatformSettings()
        {
            name = "iPhone",
            maxTextureSize = MaxTextureSize,
            crunchedCompression = true,
            format = format,
            overridden = true,
        };

        atlas.SetPlatformSettings(iosPlatformSettings);

        //Android
        TextureImporterPlatformSettings androidPlatformSettings = new TextureImporterPlatformSettings()
        {
            name = "Android",
            maxTextureSize = MaxTextureSize,
            crunchedCompression = true,
            format = format,
            overridden = true,
        };
        atlas.SetPlatformSettings(androidPlatformSettings);

        //Default
        TextureImporterPlatformSettings defaultPlatformSettings = new TextureImporterPlatformSettings()
        {
            name = "DefaultTexturePlatform",
            maxTextureSize = MaxTextureSize,
            crunchedCompression = false,
            overridden = true,
        };
        atlas.SetPlatformSettings(defaultPlatformSettings);

        AssetDatabase.ImportAsset(atlasPath);
    }

    private bool GetPlatformSettingIsAstc(TextureImporterPlatformSettings settings)
    {
        return settings.format is TextureImporterFormat.ASTC_4x4 or 
                                  TextureImporterFormat.ASTC_5x5 or 
                                  TextureImporterFormat.ASTC_6x6 or 
                                  TextureImporterFormat.ASTC_8x8 or 
                                  TextureImporterFormat.ASTC_10x10 or 
                                  TextureImporterFormat.ASTC_12x12;
    }

    private bool TrySetPlatformFormat(TextureImporter importer, TextureImporterFormat format, string platform, int maxSize)
    {
        TextureImporterPlatformSettings androidSettings = importer.GetPlatformTextureSettings(platform);
        if (!GetPlatformSettingIsAstc(androidSettings) || forceCompress)
        {
            androidSettings.overridden = true;
            androidSettings.maxTextureSize = maxSize;
            
            if (format == TextureImporterFormat.Automatic)
            {
                format = GetTextureFormat(importer);
            }
            
            androidSettings.format = format;
            importer.SetPlatformTextureSettings(androidSettings);

            return true;
        }

        return false;
    }
}